package n95_AQS原理;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

import static utils.Sleeper.sleep;

/**
 * @author fu
 * @date 2022-04-08 22:32
 * 概要：
 * ---------------------------------------------------------------
 * |                                                              |
 * |    不可重入锁：本线程加了锁，本线程继续加 将加不上锁               |
 * |         reentrantlock  是支持可重入锁的                       |
 * |=============================================================
 */
@Slf4j(topic = "c.T1")
public class T1_自定义不可重入锁 {

    public static void main(String[] args) {

        _test_一个线程重复加锁();
//        _test_两个线程互斥_串行执行();

    }

    private static void _test_一个线程重复加锁() {
        MyLock lock = new MyLock();

        new Thread(()->{
            lock.lock();
            log.debug("第 1 次加锁 ...");
            lock.lock();
            log.debug("第 2 次加锁 ...");

//            final boolean b2 = lock.tryLock();
//            log.debug("第二次加锁：{}",b2);

            try {

                log.debug("locking ...");
                sleep(1);

            } finally {

                log.debug("unlocking ...");
                lock.unlock();

            }

        }, "t1").start();
    }

    private static void _test_两个线程互斥_串行执行() {
        MyLock lock = new MyLock();

        new Thread(()->{
            lock.lock();

            try {

                log.debug("locking ...");
                sleep(1);

            } finally {

                log.debug("unlocking ...");
                lock.unlock();

            }

        }, "t1").start();

        new Thread(()->{
            lock.lock();

            try {

                log.debug("LOCKING ...");

            } finally {

                log.debug("UNLOCK ...");
                lock.unlock();

            }

        }, "t2").start();
    }


}


/**
 * [-自定义锁-] 不可重入锁
 * 锁的是 AQS 里面的state变量状态，通过CAS判断
 */
class MyLock implements Lock{

    // [--AQS同步器类--] 【独占锁】,  [-自定义锁-]要完成的大部分功能都是这个[--AQS同步器类--]来完成的
    class MySync extends AbstractQueuedSynchronizer{

        @Override // 尝试获取锁
        protected boolean tryAcquire(int arg) {// 不可重入锁 暂时不要使用参数arg

            if (compareAndSetState(0,1)) {// CAS防止其它线程来加锁
                // 加上锁了 ，设置 owner为当前线程
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }

            return false;
        }

        @Override // 尝试释放锁
        protected boolean tryRelease(int arg) {
            // 直接设置，因为owner获得锁了 ，不会有其它线程进来修改状态
            setExclusiveOwnerThread(null);
            setState(0);// 解锁, state参数是 volatile；【--- 指令重排序，所以设当前线程为null放上面，让其他线程可见 ---】
            return true;
        }

        @Override // 是否持有独占锁
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        // 返回条件变量 (这个Condition是 AQS的内部类)
        public Condition newCondition(){
            return new ConditionObject();
        }
    }

    private MySync sync = new MySync();

    @Override // 加锁 (一次不成功 放入队列中等待)
    public void lock() {

        sync.acquire(1);

    }

    @Override // 加锁 可打断 (不像synchronized不可打断，易造成死锁)
    public void lockInterruptibly() throws InterruptedException {

        sync.acquireInterruptibly(1);
    }

    @Override // 尝试加锁 (一次不成功返回false  不会死等)
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    @Override // 尝试加锁  (带超时 )
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }

    @Override // 解锁
    public void unlock() {

        sync.release(1);// tryRelease() && 还会唤醒正在阻塞的线程
    }

    @Override // 创建条件变量
    public Condition newCondition() {
        return sync.newCondition();
    }
}


